/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package org.jrill.notification;

import java.io.StringWriter;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.velocity.app.VelocityEngine;

/**
 * MassageTemplate that uses Apache Velocity to handle String Template.<br>
 * DON'T inject this as {@link MessageTemplate} but as {@link MessageTemplateFactory} into singleton instance, because MessageTemplate itself is stateful.<br>
 * Then acquire {@link MessageTemplate} instance with {@link MessageTemplateFactory#compose() }.<br>
 * This is a convinience way to use stateful instance safely in a Singleton Object.<br>
 * <br>
 * <p>
 * <strong>usage:</strong><br>
 * Spring bean definition<br>
 * <pre><blockquote>
 * &lt;bean id="helloMessageTemplate" class="org.jrill.notification.MessagetTemplateImpl"&gt;<br>
 *     &lt;property name="velocityEngine" ref="velocityEngine" /&gt;<br>
 *     &lt;property name="subject" value="Howdy, ${user}" /&gt;<br>
 *     &lt;property name="body"&gt;<br>
 *         &lt;value&gt;Hello ${user}, it's ${weather} today.&lt;/value&gt;<br>
 *     &lt;/property&gt;<br>
 * &lt;/bean&gt;<br>
 * &lt;bean id="weatherService" class="com.mycompany.WeatherService"&gt;<br>
 *     &lt;property name="messageTemplateFactory" ref="helloMessageTemplate" /&gt;<br>
 * &lt;/bean&gt;<br>
 * </blockquote></pre>
 * </p>
 * <br>
 * <p>
 * Service class<br>
 * <pre><blockquote>
 * package com.mycompany
 * public class WeatherService {
 *     private MessageTemplateFactory messageTemplateFactory;
 *     public void reportWeather(Workflow workflow, Participant currentActivityOwner, String note, String user, String weather) {
 *         //do something...
 *         MessageTemplate template = getMessageTemplateFactory.compose();
 *         HashMap map = new HashMap();
 *         map.put("user", user);
 *         map.put("weather", weather);
 *         template.setContext(map);
 *         workflow.send(currentActivityOwner, note, template);
 *     }
 * }
 * </blockquote></pre>
 * </p>
 * @author K.Waga <kzwaga@gmail.com>
 */
public class MessageTemplateImpl implements MessageTemplate, MessageTemplateFactory {
    
    protected static Log log = LogFactory.getLog(MessageTemplate.class);

    private String body;

    private String subject;

    private String linkUrl;

    private Map context;

    private VelocityEngine velocityEngine;
    
    private String fromName;

    public String evaluateSubject() {
        return evaluate(getContext(), getSubject());
    }

    public String evaluateBody() {
        return evaluate(getContext(), getBody());
    }


    public String evaluateLinkUrl() {
        return evaluate(getContext(), getLinkUrl());
    }


    /**
     * {@inheritDoc }
     * @return
     * @throws Exception
     */
    public Object getObject() throws Exception {
        MessageTemplateImpl impl = new MessageTemplateImpl();
        impl.setBody(getBody());
        impl.setLinkUrl(getLinkUrl());
        impl.setSubject(getSubject());
        impl.setVelocityEngine(getVelocityEngine());
        return impl;
    }

    /**
     * {@inheritDoc }
     * @return
     */
    public Class getObjectType() {
        return this.getClass();
    }

    /**
     * {@inheritDoc }
     * @return
     */
    public boolean isSingleton() {
        return true;
    }

    /**
     * @return the body
     */
    public String getBody() {
        return body;
    }

    /**
     * @param body the body to set
     */
    public void setBody(String body) {
        this.body = body;
    }

    /**
     * @return the subject
     */
    public String getSubject() {
        return subject;
    }

    /**
     * @param subject the subject to set
     */
    public void setSubject(String subject) {
        this.subject = subject;
    }

    /**
     * @return the linkUrl
     */
    public String getLinkUrl() {
        return linkUrl;
    }

    /**
     * @param linkUrl the linkUrl to set
     */
    public void setLinkUrl(String linkUrl) {
        this.linkUrl = linkUrl;
    }

    /**
     * @return the velocityEngine
     */
    public VelocityEngine getVelocityEngine() {
        return velocityEngine;
    }

    /**
     * @param velocityEngine the velocityEngine to set
     */
    public void setVelocityEngine(VelocityEngine velocityEngine) {
        this.velocityEngine = velocityEngine;
    }

    /**
     * @return the context
     */
    public Map getContext() {
        return context;
    }

    /**
     * @param context the context to set
     */
    public void setContext(Map context) {
        this.context = context;
    }

    /**
     * Evaluate(Merge) specified temlate with specified context.
     * @param context
     * @param template
     * @return result String of evaluation
     */
    private String evaluate(Map context, String template) {
        if (getVelocityEngine() == null) {
            log.warn("Template Engine not set.");
            return template;
        }
        StringWriter sw = new StringWriter();
        org.apache.velocity.VelocityContext vc = new org.apache.velocity.VelocityContext(context);
        getVelocityEngine().evaluate(vc, sw, this.getClass().getName(), template);
        return sw.toString();
    }

    /**
     * {@inheritDoc }
     * @param fromName 
     */
    public void setFromName(String fromName) {
        this.fromName = fromName;
    }

    /**
     * {@inheritDoc }
     * @return evaluated from name.
     */
    public String evaluateFromName() {
        return evaluate(context, fromName);
    }
    /**
     * {@inheritDoc }
     */
    public MessageTemplate compose() {
        MessageTemplateImpl impl = new MessageTemplateImpl();
        impl.setBody(getBody());
        impl.setLinkUrl(getLinkUrl());
        impl.setSubject(getSubject());
        impl.setVelocityEngine(getVelocityEngine());
        return impl;
    }

}
